using System.Security.Cryptography;
using System.Text;

namespace Vin.Tool.Core.EncryptCategory;

public class AesGcmEncryptTool
{
    /// <summary>
    /// 生成256位AES-GCM加密密钥
    /// </summary>
    /// <returns>密钥字节数组</returns>
    public static byte[] GenerateKey(int keySize = 256)
    {
        if (keySize != 128 && keySize != 192 && keySize != 256)
            throw new ArgumentException("Key size must be 128, 192, or 256 bits.", nameof(keySize));

        byte[] key = new byte[keySize / 8];
        RandomNumberGenerator.Fill(key);
        return key;
    }
    
    /// <summary>
    /// 从Base64字符串加载密钥
    /// </summary>
    /// <param name="base64Key">Base64编码的密钥字符串</param>
    /// <returns>密钥字节数组</returns>
    public static byte[] LoadKey(string base64Key)
    {
        if (string.IsNullOrEmpty(base64Key))
            throw new ArgumentNullException(nameof(base64Key));
            
        return Convert.FromBase64String(base64Key);
    }
    
    /// <summary>
    /// 将密钥导出为Base64字符串
    /// </summary>
    /// <param name="key">密钥字节数组</param>
    /// <returns>Base64编码的密钥字符串</returns>
    public static string ExportKey(byte[] key)
    {
        return Convert.ToBase64String(key);
    }
    
    /// <summary>
    /// 加密数据
    /// </summary>
    /// <param name="key">加密密钥</param>
    /// <param name="data">要加密的字符串数据</param>
    /// <param name="ivSize">IV（初始向量）的大小，默认为12字节</param>
    /// <returns>包含IV和加密数据的字节数组</returns>
    public static byte[] EncryptData(byte[] key, string data, int ivSize = 12)
    {
        if (string.IsNullOrEmpty(data))
            throw new ArgumentNullException(nameof(data));
            
        if (ivSize <= 0)
            throw new ArgumentOutOfRangeException(nameof(ivSize), "IV大小必须大于0");
            
        // 生成随机IV
        byte[] iv = new byte[ivSize];
        RandomNumberGenerator.Fill(iv);
        
        // 将数据转换为字节数组
        byte[] dataBytes = Encoding.UTF8.GetBytes(data);
        
        // 加密操作
        using (var aes = new AesGcm(key))
        {
            byte[] ciphertext = new byte[dataBytes.Length];
            byte[] tag = new byte[16]; // GCM标签固定为16字节
            
            aes.Encrypt(iv, dataBytes, ciphertext, tag);
            
            // 组合IV、加密数据和标签（格式：IV + 加密数据 + 标签）
            byte[] combined = new byte[iv.Length + ciphertext.Length + tag.Length];
            Buffer.BlockCopy(iv, 0, combined, 0, iv.Length);
            Buffer.BlockCopy(ciphertext, 0, combined, iv.Length, ciphertext.Length);
            Buffer.BlockCopy(tag, 0, combined, iv.Length + ciphertext.Length, tag.Length);
            
            return combined;
        }
    }
    
    /// <summary>
    /// 解密数据
    /// </summary>
    /// <param name="key">解密密钥</param>
    /// <param name="encryptedData">包含IV和加密数据的字节数组</param>
    /// <param name="ivSize">IV（初始向量）的大小，默认为12字节</param>
    /// <returns>解密后的字符串数据</returns>
    public static string DecryptData(byte[] key, byte[] encryptedData, int ivSize = 12)
    {
        if (encryptedData == null || encryptedData.Length <= ivSize + 16)
            throw new ArgumentException("加密数据无效或不完整", nameof(encryptedData));
            
        if (ivSize <= 0)
            throw new ArgumentOutOfRangeException(nameof(ivSize), "IV大小必须大于0");
            
        // 分离IV、加密数据和标签
        byte[] iv = new byte[ivSize];
        byte[] ciphertext = new byte[encryptedData.Length - ivSize - 16];
        byte[] tag = new byte[16];
        
        Buffer.BlockCopy(encryptedData, 0, iv, 0, ivSize);
        Buffer.BlockCopy(encryptedData, ivSize, ciphertext, 0, ciphertext.Length);
        Buffer.BlockCopy(encryptedData, ivSize + ciphertext.Length, tag, 0, 16);
        
        // 解密操作
        using (var aes = new AesGcm(key))
        {
            byte[] plaintext = new byte[ciphertext.Length];
            aes.Decrypt(iv, ciphertext, tag, plaintext);
            
            return Encoding.UTF8.GetString(plaintext);
        }
    }
}